#ifndef __VANILA_DATA_STRUCTURE_OBJECT_HH__
#define __VANILA_DATA_STRUCTURE_OBJECT_HH__

#include "vanila/object.h"
#include <vector>
#include <map>
#include <set>

namespace vanila
{
class ObjectList : public Object
{
public:
    //! \brief constructor and destructor
    ObjectList();
    ObjectList(std::vector<Value> list);
    virtual ~ObjectList() noexcept override {};

    //! \brief print object list
    virtual void print(bool callStr = true) const override;

    //! \brief wheather this == that
    virtual bool equal(const Object* that) const override;

    //! \brief add two object
    virtual Value add(const Object* that) const override;

public:
    //! \brief append a value to list
    //! \param[in] value
    void append(const Value& value)
    { this->_list.push_back(value); }

    //! \brief insert a value to specify index 
    bool insert(size_t index, const Value& value);

    //! \brief earse a value in specify index
    bool pop(size_t index) noexcept;

    //! \brief operator [], act as a vector
    Value& operator[] (size_t index) noexcept
    { return this->_list[index]; }

    //! \brief operator [], act as a vector
    const Value& operator[] (size_t index) const noexcept
    { return this->_list[index]; }
    
    //! \brief get the value by specify index
    bool get(int64_t index, Value& value) const noexcept;

private:
    std::vector<Value> _list;

public:
    std::vector<Value>& list() noexcept
    { return this->_list; }

    const std::vector<Value>& list() const noexcept
    { return this->_list; }
};

class ObjectDictionary : public Object
{
public:
    ObjectDictionary();
    ObjectDictionary(std::map<Value, Value> dict);
    virtual ~ObjectDictionary() noexcept override {};

    //! \brief print object list
    virtual void print(bool callStr = true) const override;

    //! \brief wheather this == that
    virtual bool equal(const Object* that) const override;

public:
    //! \brief add a key-value pair into dict
    void add(const Value& key, const Value& value)
    { this->_dict[key] = value; }

    //! \brief get the value by specify key
    bool get(const Value& key, Value& value);

    //! \brief set the value by specify key
    void set(const Value& key, const Value& value);

private:
    std::map<Value, Value> _dict;

public:
    std::map<Value, Value>& dict() noexcept
    { return this->_dict; }

    const std::map<Value, Value>& dict() const noexcept
    { return this->_dict; }
};

class ObjectSet : public Object
{
public:
    ObjectSet();
    ObjectSet(std::set<Value> set);
    virtual ~ObjectSet() noexcept override {}

    //! \brief print object set
    virtual void print(bool callStr = true) const override;

    //! \brief wheather this == that
    virtual bool equal(const Object* that) const override;

public:
    //! \brief add a key-value pair into dict
    void add(const Value& value)
    { this->_set.insert(value); }

    //! \brief weather the set contains the value
    bool contain(const Value& value);

private:
    std::set<Value> _set;

public:
    std::set<Value>& set() noexcept
    { return this->_set; }

    const std::set<Value>& set() const noexcept
    { return this->_set; }
};

}

#endif